package com.wjc.hibernate.dao.impl;

import java.lang.reflect.Method;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;

import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;
import javax.persistence.TypedQuery;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;
import javax.persistence.metamodel.Attribute;
import javax.persistence.metamodel.EntityType;
import javax.persistence.metamodel.Metamodel;

import org.springframework.transaction.annotation.Transactional;

import com.wjc.hibernate.bean.User;
import com.wjc.hibernate.dao.UserDao;

@Transactional
public class UserDaoImpl implements UserDao {

	@PersistenceContext
	private EntityManager entityManager;

	@Override
	public void persist(User user) {
		// TODO Auto-generated method stub
		entityManager.persist(user);
	}

	@Override
	public void delete(User user) {
		// TODO Auto-generated method stub

	}

	@Override
	public void merge(User user) {
		// TODO Auto-generated method stub
		entityManager.merge(user);
	}

	@Override
	public User find(Map<String, Object> keyVlaues) {
		// TODO Auto-generated method stub
		CriteriaBuilder cb = entityManager.getCriteriaBuilder();
		CriteriaQuery<User> cq = cb.createQuery(User.class);
		Root<User> userRoot = cq.from(User.class);

		cq = cq.select(userRoot);

		for (Entry<String, Object> entry : keyVlaues.entrySet()) {
			cq = cq.where(cb.equal(userRoot.get(entry.getKey()), entry.getValue()));
		}
		Query query = entityManager.createQuery(cq);
		List<?> users = query.getResultList();
		if (users.size() > 0) {
			return (User) users.get(0);
		} else {
			return null;
		}
	}

	@Override
	public List<User> findByExample(User example) {
		// Class<User> clazz = example.getPersistableClass();
		try {
			CriteriaBuilder cb = entityManager.getCriteriaBuilder();
			CriteriaQuery<User> cq = cb.createQuery(User.class);
			Root<User> r = cq.from(User.class);
			Predicate p = cb.conjunction();
			Metamodel mm = entityManager.getMetamodel();
			EntityType<User> et = mm.entity(User.class);
			Set<Attribute<? super User, ?>> attrs = et.getAttributes();
			for (Attribute<? super User, ?> a : attrs) {
				String name = a.getName();
				String javaName = a.getJavaMember().getName();
				String getter = "get" + javaName.substring(0, 1).toUpperCase() + javaName.substring(1);
				Method m = example.getClass().getMethod(getter, (Class<?>[]) null);
				if (m.invoke(example, (Object[]) null) != null) {
					p = cb.and(p, cb.equal(r.get(name), m.invoke(example, (Object[]) null)));
				}
			}
			cq.select(r).where(p);
			TypedQuery<User> query = entityManager.createQuery(cq);
			return query.getResultList();
		} catch (Exception e) {
			e.printStackTrace();
			return null;
		}

	}

	public EntityManager getEntityManager() {
		return entityManager;
	}

	public void setEntityManager(EntityManager entityManager) {
		this.entityManager = entityManager;
	}
}
